"""
FastAPI依赖注入系统
"""

from typing import AsyncGenerator, Generator
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from sqlalchemy.orm import Session
from sqlalchemy.ext.asyncio import AsyncSession

from app.database import get_db, get_async_db
from app.utils.redis_client import get_redis_client, get_async_redis_client
from app.utils.security import decode_access_token
from app.models import User
from app.config import settings

# JWT认证
security = HTTPBearer()


async def get_current_user(
    credentials: HTTPAuthorizationCredentials = Depends(security),
    db: AsyncSession = Depends(get_async_db)
) -> User:
    """
    获取当前认证用户
    """
    try:
        # 解码JWT令牌
        payload = decode_access_token(credentials.credentials)
        user_id = payload.get("sub")
        
        if user_id is None:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="无效的认证令牌",
                headers={"WWW-Authenticate": "Bearer"},
            )
        
        # 查询用户
        from sqlalchemy import select
        result = await db.execute(select(User).where(User.id == int(user_id)))
        user = result.scalar_one_or_none()
        
        if user is None:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="用户不存在",
                headers={"WWW-Authenticate": "Bearer"},
            )
        
        if not user.is_active:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="用户账号已被禁用",
                headers={"WWW-Authenticate": "Bearer"},
            )
        
        return user
        
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="认证失败",
            headers={"WWW-Authenticate": "Bearer"},
        )


async def get_current_active_user(
    current_user: User = Depends(get_current_user)
) -> User:
    """
    获取当前活跃用户
    """
    if not current_user.is_active:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="用户账号已被禁用"
        )
    return current_user


def get_sync_db() -> Generator[Session, None, None]:
    """
    获取同步数据库会话（用于Celery任务）
    """
    yield from get_db()


async def get_redis() -> AsyncGenerator:
    """
    获取异步Redis客户端
    """
    redis = await get_async_redis_client()
    try:
        yield redis
    finally:
        # Redis连接池会自动管理连接
        pass


def get_sync_redis():
    """
    获取同步Redis客户端（用于Celery任务）
    """
    return get_redis_client()


# 服务依赖注入
async def get_monitor_service():
    """获取监控服务"""
    from app.services.monitor_service import MonitorService
    return MonitorService()


async def get_notification_service():
    """获取通知服务"""
    from app.services.notification_service import NotificationService
    return NotificationService()


async def get_auth_service():
    """获取认证服务"""
    from app.services.auth_service import AuthService
    return AuthService()


async def get_balance_service():
    """获取余额服务"""
    from app.services.balance_service import BalanceService
    return BalanceService()


# 权限检查依赖
async def require_sufficient_balance(
    current_user: User = Depends(get_current_active_user),
    db: AsyncSession = Depends(get_async_db)
) -> User:
    """
    检查用户余额是否充足
    """
    # 刷新用户余额信息
    await db.refresh(current_user, ["balance"])
    
    if current_user.balance.amount <= 0:
        raise HTTPException(
            status_code=status.HTTP_402_PAYMENT_REQUIRED,
            detail="余额不足，请先充值"
        )
    
    return current_user


async def require_admin_user(
    current_user: User = Depends(get_current_active_user)
) -> User:
    """
    检查是否为管理员用户
    """
    if not current_user.is_admin:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="需要管理员权限"
        )
    
    return current_user


# 分页依赖
class PaginationParams:
    """分页参数"""
    
    def __init__(self, page: int = 1, size: int = 20):
        self.page = max(1, page)
        self.size = min(100, max(1, size))  # 限制每页最多100条
        self.offset = (self.page - 1) * self.size


def get_pagination_params(page: int = 1, size: int = 20) -> PaginationParams:
    """获取分页参数"""
    return PaginationParams(page, size)


# 缓存依赖
class CacheService:
    """缓存服务"""
    
    def __init__(self, redis_client):
        self.redis = redis_client
    
    async def get(self, key: str):
        """获取缓存"""
        return await self.redis.get(key)
    
    async def set(self, key: str, value: str, ex: int = None):
        """设置缓存"""
        return await self.redis.set(key, value, ex=ex)
    
    async def delete(self, key: str):
        """删除缓存"""
        return await self.redis.delete(key)


async def get_cache_service(
    redis = Depends(get_redis)
) -> CacheService:
    """获取缓存服务"""
    return CacheService(redis)


# 限流依赖
async def rate_limit_check(
    request_id: str,
    limit: int = 100,
    window: int = 3600,
    redis = Depends(get_redis)
):
    """
    限流检查
    
    Args:
        request_id: 请求标识（如用户ID、IP等）
        limit: 限制次数
        window: 时间窗口（秒）
    """
    key = f"rate_limit:{request_id}"
    
    # 获取当前计数
    current = await redis.get(key)
    
    if current is None:
        # 首次请求，设置计数为1
        await redis.set(key, 1, ex=window)
        return True
    
    if int(current) >= limit:
        raise HTTPException(
            status_code=status.HTTP_429_TOO_MANY_REQUESTS,
            detail=f"请求过于频繁，请在{window}秒后重试"
        )
    
    # 增加计数
    await redis.incr(key)
    return True
